import plotly.graph_objects as go
import pandas as pd
import numpy as np
import os
import sys
# Lectura del dataframe
url = 'https://raw.githubusercontent.com/iruiper/Cyberattacks-History/master/data/01_clean/EstadisticasAtaques2017_2020_Input.csv'
df = pd.read_csv(url, sep=';', decimal=',', encoding='utf-8')
# Suprimimos los target class que sean X,Y o Z y los continentes desconocidos.
cols_plot = ['Continent', 'NumeroAtaques', 'Code_target_class', 'Desc_target_class']
df_plot = df[(df.Continent != 'Desconocido') & ~(df.Code_target_class.isin(['X', 'Y', 'Z']))][cols_plot]
# Creamos una variable adicional que segregará entre ataques internacionales y unicontinentales
df_plot.loc[:, 'Kind'] = np.where(df_plot.Continent == 'International', '<b>International</b>', '<b>Single <br>Continent</b>')
# Datos para generar el gráfico general del número de ataques internacionales vs single continent
df_plot_general = df_plot[['Kind', 'NumeroAtaques']].groupby('Kind', as_index=False).sum()
# Datos para generar el gráfico general de número de ataques internacionales vs single continent para public class
df_plot_general_public = df_plot[df_plot.Code_target_class=='O'][['Kind', 'NumeroAtaques']].groupby('Kind', as_index=False).sum()
fig = go.Figure()
# Se añaden en el gráfico los ataques totales
fig.add_trace(
go.Bar(
x=df_plot_general.NumeroAtaques,
y=df_plot_general.Kind,
text=df_plot_general.NumeroAtaques,
textposition='outside',
orientation='h',
marker=dict(color='rgba(130,201,241,0.4)'),
hoverinfo='skip',
name='Todas las empresas',
cliponaxis=False
)
)
# Se añaden en el gráfico los ataques para el sector público
fig.add_trace(
go.Bar(
x=df_plot_general_public.NumeroAtaques,
y=df_plot_general_public.Kind,
text=df_plot_general_public.NumeroAtaques,
textposition='outside',
orientation='h',
marker=dict(color='rgba(14,76,112,0.9)'),
hoverinfo='skip',
name='Empresas sector público'
)
)
# Se modifican algunas características visuales del gráfico como axes, legend, etc.
fig.update_layout(
barmode='overlay',
title=dict(
text = f'<b>Distribución ataques<br>internacionales vs continentales</b>',
x = 0.5,
xanchor = 'center',
yanchor = 'top'),
titlefont=dict(size=18),
plot_bgcolor='white',
xaxis=dict(showgrid=False, visible=False, zeroline=False, autorange=True, automargin=True),
yaxis=dict(showgrid=False, visible=True, zeroline=False, autorange=True),
showlegend=True,
legend_orientation='h'
)
fig.show('notebook')
# Se generan los datos para el gráfico de barras de los ataques totales en función del continente. Primero
# se descartan aquellos ataques internacionales.
df_continent = df_plot[df_plot.Continent != 'International']
# Se agrupa cada continente y se suman los ataques.
df_continent_total = df_continent[['Continent', 'NumeroAtaques']].groupby('Continent', as_index=False).sum()
# Se ordenan los datos para mejorar facilitar las comparaciones entre elementos del gráfico.
df_continent_total.sort_values('NumeroAtaques', ascending=True, inplace=True)
df_continent_total
# Se generan los datos para el gráfico de barras de los ataques totales en función del continente. Se seleccionan
# únicamente los ataques dirigidos al sector público.
df_continent_total_public = df_continent[df_continent.Code_target_class == 'O'][['Continent', 'NumeroAtaques']].groupby('Continent', as_index=False).sum()
# Se ordenan los datos para mejorar facilitar las comparaciones entre elementos del gráfico.
df_continent_total_public.sort_values('NumeroAtaques', ascending=True, inplace=True)
df_continent_total_public
fig = go.Figure()
# Se añaden en el gráfico los ataques totales por continente
fig.add_trace(
go.Bar(
x=df_continent_total.NumeroAtaques,
y=df_continent_total.Continent,
text=df_continent_total.NumeroAtaques,
textposition='outside',
orientation='h',
marker=dict(color='rgba(130,201,241,0.4)'),
hoverinfo='skip',
name='Todas las empresas',
cliponaxis=False
)
)
# Se añaden en el gráfico los ataques totales por continente para empresas del sector público
fig.add_trace(
go.Bar(
x=df_continent_total_public.NumeroAtaques,
y=df_continent_total_public.Continent,
text=df_continent_total_public.NumeroAtaques,
textposition='inside',
orientation='h',
marker=dict(color='rgba(14,76,112,0.9)'),
hoverinfo='skip',
name='Empresas sector público'
)
)
# Modificaciones estéticas del gráfico.
fig.update_layout(
barmode='overlay',
title=dict(
text = f'<b>Distribución ataques<br>continentales</b>',
x = 0.5,
xanchor = 'center',
yanchor = 'top'),
titlefont=dict(size=18),
plot_bgcolor='white',
xaxis=dict(showgrid=False, visible=False, zeroline=False, autorange=True, automargin=True),
yaxis=dict(showgrid=False, visible=True, zeroline=False, autorange=True),
showlegend=True,
legend_orientation='h'
)
fig.show('notebook')
fig = go.Figure()
# Se normalizan los ataques para el sector público en función de los ataques totales en cada continente.
df_norm = df_continent_total_public.copy()
df_norm.set_index('Continent', inplace=True, drop=False)
df_norm.loc[:, 'Total'] = df_continent_total.set_index('Continent').NumeroAtaques
df_norm.loc[:, 'Norm'] = df_norm.NumeroAtaques / df_norm.Total
df_norm.loc[:, 'Txt'] = df_norm.Norm.apply(lambda x: str(round(x*100,2)) + '%')
df_norm.sort_values('Norm', ascending=True, inplace=True)
df_norm
# Gráfico de barras con los ataques normalizdos
fig.add_trace(
go.Bar(
x=df_norm.Norm,
y=df_norm.Continent,
text=df_norm.Txt,
textposition='inside',
orientation='h',
marker=dict(color='rgba(14,76,112,0.9)'),
hoverinfo='skip',
name='Empresas sector público'
)
)
# modificaciones estéticas del gráfico
fig.update_layout(
barmode='overlay',
title=dict(
text = f'<b>Distribución normalizada de ataques<br>continentales</b>',
x = 0.5,
xanchor = 'center',
yanchor = 'top'),
titlefont=dict(size=18),
plot_bgcolor='white',
xaxis=dict(showgrid=False, visible=False, zeroline=False, autorange=True, automargin=True),
yaxis=dict(showgrid=False, visible=True, zeroline=False, autorange=True),
showlegend=True,
legend_orientation='h'
)
fig.show('notebook')
# Diccionario que permitirá ajustar los labels dentro del gráfico
adjust_label = {
'Public administration and defence, compulsory social security': 'Public administration<br>and defence, compulsory<br>social security',
'Financial and insurance activities': 'Financial and<br>insurance activities',
'Information and communication': 'Information and<br>communication',
'Arts entertainment and recreation': 'Arts entertainment<br>and recreation',
'Human health and social work activities': 'Human health and<br>social work activities'
}
# Nos quedamos exclusivamente con los ataques producidos en europa
df_europa = df_plot[df_plot.Continent == 'Europa']
# Agregamos el número de ataques en función del sector al que afectan.
df_europa_total = df_europa[['Code_target_class', 'Desc_target_class', 'NumeroAtaques']].groupby(['Code_target_class','Desc_target_class'], as_index=False).sum()
# Se ordenan los datos para mejorar facilitar las comparaciones entre elementos del gráfico.
df_europa_total.sort_values('NumeroAtaques', ascending=True, inplace=True)
# Asignamos un color distinto a los ataques del sector publico para facilitar la identificación de elementos en el gráfico
df_europa_total.loc[:, 'color'] = np.where(df_europa_total['Code_target_class'] == 'O',
'rgba(14,76,112,0.9)',
'rgba(198,202,204,1)')
# Nos quedamos con el top 5 de sectores atacados. Como el df esta ordenado en forma ascendente, el top 5 se encuentra
# en las últimas 5 posiciones
df_europa_plot = df_europa_total.tail(5)
# Ajustamos las etiquetas a través del diccionario
df_europa_plot.Desc_target_class = df_europa_plot.Desc_target_class.map(adjust_label)
fig = go.Figure()
# Generación del grafico de barras con el top 5 de empresas europeas atacadas
fig.add_trace(
go.Bar(
x=df_europa_plot.NumeroAtaques,
y=df_europa_plot.Desc_target_class,
text=df_europa_plot.NumeroAtaques,
textposition='outside',
orientation='h',
marker=dict(color=df_europa_plot.color),
hoverinfo='skip',
name='Todas las empresas',
cliponaxis=False
)
)
# Modificaciones estéticas del gráfico.
fig.update_layout(
barmode='overlay',
title=dict(
text = f'<b>Distribución ataques europeos<br>según el tipo de empresa</b>',
x = 0.5,
xanchor = 'center',
yanchor = 'top'),
titlefont=dict(size=18),
plot_bgcolor='white',
xaxis=dict(showgrid=False, visible=False, zeroline=False, autorange=True, automargin=True),
yaxis=dict(showgrid=False, visible=True, zeroline=False, autorange=True, automargin=True),
showlegend=False,
legend_orientation='h',
margin=dict(l=100)
)
fig.show('notebook')